﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace Quake3LogParser {
	public partial class Form1 : Form {
		private class Kill {
			public Kill(string killer, string victim, string weapon) {
				Killer = killer;
				Victim = victim;
				Weapon = weapon;
			}

			public string Killer { get; set; }
			public string Victim { get; set; }
			public string Weapon { get; set; }
		}

		private class KillList : List<Kill> { }

		private readonly Regex _killRegex = new Regex(@".+ ([\^A-Za-z0-9@]+) killed ([\^A-Za-z0-9@]+) by ([\^A-Za-z0-9_@]+).+");

		private KillList _kills = new KillList();

		public Form1() {
			InitializeComponent();
		}

		private void ChooseFile_Click(object sender, EventArgs e) {
			if (openFileDialog1.ShowDialog() == DialogResult.OK) {
				LogFileName.Text = openFileDialog1.FileName;
			}
		}

		private void Parse_Click(object sender, EventArgs e) {
			StreamReader streamReader = File.OpenText(LogFileName.Text);

			string line;
			while (!String.IsNullOrEmpty(line = streamReader.ReadLine())) {
				if (_killRegex.IsMatch(line)) {
					Match match = this._killRegex.Match(line);
					Kill kill = new Kill(match.Groups[1].Value, match.Groups[2].Value, match.Groups[3].Value);
					this._kills.Add(kill);
				}
			}

			Analyze();
		}

		private void Analyze() {
			IEnumerable<string> killers = (from kill in this._kills select kill.Killer).Distinct();
			IEnumerable<string> victims = (from kill in this._kills select kill.Victim).Distinct();

			IEnumerable<string> players = (killers.Union(victims)).Distinct();

			WriteLog(String.Format("Detected {0} players:", players.Count()));

			foreach (string player in players) {
				WriteLog(String.Format("--=== Player: {0} ===--", player));
				IEnumerable<Kill> playerKills = from kill in this._kills where kill.Killer.Equals(player) && kill.Victim != player select kill;
				IEnumerable<Kill> playerSuicides = from kill in this._kills where kill.Killer.Equals(player) && kill.Victim.Equals(player) select kill;
				IEnumerable<Kill> playerDeaths = from kill in this._kills where kill.Killer != player && kill.Victim.Equals(player) select kill;

				WriteLog("-General stats");
				int playerKillsCount = playerKills.Count();
				int playerDeathsCount = playerDeaths.Count();
				int playerSuicidesCount = playerSuicides.Count();

				WriteLog(String.Format("Total kills: {0}", playerKillsCount));
				WriteLog(String.Format("Total deaths: {0}", playerDeathsCount));
				WriteLog(String.Format("Total suicides: {0}", playerSuicidesCount));
				WriteLog(String.Format("Kill/death ratio: {0}", Math.Round(1.0 * playerKillsCount /  playerDeathsCount, 3)));

				WriteLog("-Weapon kill stats");
				var playerWeaponGroup = from kill in playerKills group kill by kill.Weapon into g select new { Weapon = g.Key, Count = g.Count() };
				foreach (var playerWeapon in playerWeaponGroup) {
					WriteLog(String.Format("{0}:{1}", playerWeapon.Weapon, playerWeapon.Count));
				}

				WriteLog("-Player victims stats");
				var playerVictimsGroup = from kill in playerKills group kill by kill.Victim into g select new { Victim = g.Key, Count = g.Count() };
				foreach (var playerVictim in playerVictimsGroup) {
					WriteLog(String.Format("{0}:{1}", playerVictim.Victim, playerVictim.Count));
				}

				WriteLog("-------------------------------------------------------------------------------------------------------");
			}
		}

		private void WriteLog(string message) {
			Log.Text += string.Format("{0}\r\n", message);
		}
	}
}
